/**
 * 
 */
package filesystem;

import hibernate.Album;
import hibernate.Artist;
import hibernate.InvalidSong;
import hibernate.Song;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import model.IAlbum;
import model.IArtist;
import model.IInvalidSong;
import model.ISong;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.farng.mp3.MP3File;
import org.farng.mp3.id3.AbstractID3;

import web.IConstants;

/**
 * @author isaac
 *
 */
public class MusicFinder {
	protected final Log logger = LogFactory.getLog(getClass());
	
	private Map<String, IArtist> artists = new HashMap<String, IArtist>();
	private Map<String, IAlbum> albums = new HashMap<String, IAlbum>();
	private List<IInvalidSong> invalidSongs = new ArrayList<IInvalidSong>();
	private String searchPath;
	
	public MusicFinder() {}
	
	public  void parseFiles(String scannPath) {
		File dir = new File(scannPath);
		String[] fileNames = dir.list();
		MP3File mp3;
		
		for(int i=0;i<fileNames.length;i++) {
			String path = dir.getAbsolutePath();
			String fileName = fileNames[i];
			
			File f;
			f = new File(path+IConstants.Filesystem.PATH_SEPERATOR_NIX+fileName);
			
			if(f == null) {
				logger.debug(" *** Null file at: "+fileName+" *** ");
				continue;
			}
			
			if(f.isDirectory()) {
				parseFiles(f.getAbsolutePath());
				continue;
			}
		
			//only parse mp3, m4a, mp4 and ogg files
			if(!(fileName.indexOf("mp3") > 0 || 
			     fileName.indexOf("m4a") > 0 ||
			     fileName.indexOf("mp4") > 0 ||
			     fileName.indexOf("ogg") > 0)) {
				continue;
			}
			
			try {
				mp3 = new MP3File(f);				
			} catch (Exception e) {
				e.printStackTrace();
				logger.debug("something is wrong with: "+fileName);
				if(!f.isDirectory()) {
					IInvalidSong is = new InvalidSong();
					is.setName(fileName);
					is.setPath(f.getAbsolutePath());
					invalidSongs.add(is);
				}
				
				continue;
			}
			
			try {
				AbstractID3 tag = mp3.getID3v2Tag();
				
				if(tag == null || "".equals(tag.getAlbumTitle())) {
					//Check v1 tag
					tag = mp3.getID3v1Tag();
					if(tag == null || tag.getAlbumTitle().equals("")) {
						IInvalidSong is = new InvalidSong();
						is.setName(fileName);
						is.setPath(f.getAbsolutePath());
						invalidSongs.add(is);
						continue;
					}
				}
				
				IAlbum album = albums.get(tag.getAlbumTitle());
				IArtist artist = artists.get(tag.getLeadArtist());
	
				ISong song = new Song();
				
				song.setName(tag.getSongTitle());
			
				try {
					String trackNumber = tag.getTrackNumberOnAlbum();
					//get rid of the stupid slash
					if(trackNumber.indexOf("/") != -1) {
						trackNumber = trackNumber.substring(0, trackNumber.indexOf("/"));
					}
					
					song.setTrackNumber(trackNumber);
				} catch (Exception e) {
					e.printStackTrace();
					logger.debug("Couldn't find track # for "+fileName+", oh well we'll deal with this later.");
				}
				
				song.setPath(f.getAbsolutePath());
			
				if(artist == null) {
					artist  = new Artist();
					artist.setName(tag.getLeadArtist());
					artists.put(tag.getLeadArtist(), artist);
					logger.debug("Just found artist: "+artist.getName());
				}
				
				if(album == null) {
					album = new Album();
					album.setArtist(artist);
					album.setName(tag.getAlbumTitle());
					albums.put(tag.getAlbumTitle(), album);
					
					logger.debug("Just found album ("+albums.size()+"): "+tag.getLeadArtist()+" - "+tag.getAlbumTitle());
				}
				
				album.addSong(song);
				artist.getAlbums().add(album);
			} catch (Exception e) {
				e.printStackTrace();
				IInvalidSong is = new InvalidSong();
				is.setName(fileName);
				is.setPath(f.getAbsolutePath());
				invalidSongs.add(is);
			}
		}
	}
	
	/**
	 * @return Returns the albums.
	 */
	public Map<String, IAlbum> getAlbums() {
		return albums;
	}
	/**
	 * @param albums The albums to set.
	 */
	public void setAlbums(Map<String, IAlbum> albums) {
		this.albums = albums;
	}
	/**
	 * @return Returns the artists.
	 */
	public Map<String, IArtist> getArtists() {
		return artists;
	}
	/**
	 * @param artists The artists to set.
	 */
	public void setArtists(Map<String, IArtist> artists) {
		this.artists = artists;
	}
	/**
	 * @return Returns the invalidSongs.
	 */
	public List<IInvalidSong> getInvalidSongs() {
		return invalidSongs;
	}
	/**
	 * @param invalidSongs The invalidSongs to set.
	 */
	public void setInvalidSongs(List<IInvalidSong> invalidSongs) {
		this.invalidSongs = invalidSongs;
	}

	/**
	 * @return Returns the searchPath.
	 */
	public String getSearchPath() {
		return searchPath;
	}

	/**
	 * @param searchPath The searchPath to set.
	 */
	public void setSearchPath(String searchPath) {
		this.searchPath = searchPath;
	}
}
